
namespace Alogient.Cameleon.Sdk.UI.WebControls
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Text;
    using Alogient.Cameleon.Forms.Sdk.Items;
    using Alogient.Cameleon.Forms.Sdk.Controls;
    using System.Net.Mail;
    using System.Web;

    public class FormEventArgs : EventArgs
    {
        public Submission Submission { get; set; }
    }

    public delegate void CompletedFormHandler(object sender, FormEventArgs e);

    [DefaultProperty("Value")]
    [ToolboxData("<{0}:CMForm runat=server></{0}:CMForm>")]
    public class CMForm : Panel
    {
        internal const string SummaryButtonsIDFormat = "SummaryButtons_{0}";
        internal const string SummaryContainerIDFormat = "SummaryContainer_{0}";
        internal const string PagePanelIDFormat = "PagePanel_{0}";

        protected string value;

        public CMForm()
        {
            NavID = NavigationController.GetNavID();
            CultureCode = NavigationController.GetCultureCode();
        }

        protected void LoadFieldValue()
        {
            this.LoadValue(this.NavID, this.BindField);
        }

        protected virtual void LoadValue(int navID, string name)
        {
            if (!string.IsNullOrEmpty(name))
            {
                this.value = CMServices.GetPage(navID, this.CultureCode).Elements[name].Value;
            }
        }

        #region Properties Accessors

        [Category("Cameleon")]
        [Browsable(true)]
        public string BindField { get; set; }

        [Category("Cameleon")]
        [Browsable(true)]
        public int NavID { get; set; }

        [Category("Cameleon")]
        [Browsable(true)]
        public string CultureCode { get; set; }

        #endregion

        public string Value
        {
            get
            {
                if (this.value == null)
                {
                    this.LoadFieldValue();
                }

                return this.value;
            }
        }

        Forms.Sdk.Items.Form form = null;
        public Forms.Sdk.Items.Form TheForm
        {
            get
            {
                if (this.form == null)
                {
                    int formID = Int32.Parse(Value);
                    this.form = new Forms.Sdk.Items.Form(formID, this.CultureCode);
                }

                return this.form;
            }
        }

        protected bool FormEnabled
        {
            get
            {
                return Forms.Sdk.Util.ConfigurationUtils.FormManagerEnabled && !string.IsNullOrEmpty(this.Value) && this.TheForm != null && ((CMServices.IsLive && this.TheForm.VisibleLive) || (!CMServices.IsLive && this.TheForm.VisiblePreview));
            }
        }

        public event CompletedFormHandler Completed;

        protected virtual void OnCompleted(FormEventArgs e)
        {
            if (this.Completed != null)
            {
                this.Completed(this, e);
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (this.FormEnabled)
            {
                // If Form Is Visible
                if ((CMServices.IsLive && this.TheForm.VisibleLive) || (!CMServices.IsLive && this.TheForm.VisiblePreview))
                {
                    if (this.TheForm.AnswerOnce)
                    {
                        // Check for Cookie
                        if (this.FormCookieExists(this.Page.Request, this.TheForm.ID) ||
                            Forms.Sdk.Util.WebUtil.MembershipEnabled() 
                            // &&  Forms.Sdk.DAL.DAL.FormHasUserSubmissions(TheForm.ID, 
                                // Forms.Sdk.Util.WebUtil.GetCurrentUsername(), 
                                // Forms.Sdk.Util.WebUtil.GetCurrentUserPKID()))
                            )
                        {
                            this.Visible = false;
                        }
                    }

                    // Script Manager (AJAX)
                    this.GenerateScriptManager();

                    this.CssClass = "FormClass";
                    if (!string.IsNullOrEmpty(this.TheForm.CSS))
                    {
                        this.CssClass = this.TheForm.CSS;
                    }

                    if (this.HasPagination(this.TheForm))
                    {
                        // Generate Pages Header
                        this.GeneratePagesHeader(this.TheForm);
                    }

                    // GenerateHiddenFields
                    this.GenerateHiddenFields();

                    // Generate Pages
                    this.GeneratePages(this.TheForm);

                    // Generate Step buttons if summary
                    if (this.TheForm.ShowSummary)
                    {
                        var summaryContainer = new PlaceHolder();
                        this.Controls.Add(summaryContainer);
                        summaryContainer.ID = string.Format(SummaryContainerIDFormat, this.TheForm.ID.ToString());

                        var summaryButtons = new PlaceHolder();
                        this.Controls.Add(summaryButtons);

                        summaryButtons.ID = string.Format(SummaryButtonsIDFormat, this.TheForm.ID.ToString());
                        summaryButtons.Visible = false;

                        var backButton = new System.Web.UI.WebControls.Button
                                             {
                                                 Text = Alogient.Cameleon.Forms.Sdk.Util.WebUtil.GetLabelsRessource("Back"),
                                                 CausesValidation = false
                                             };
                        backButton.Click += this.backButton_Click;

                        var nextButton = new System.Web.UI.WebControls.Button
                                             {
                                                 Text = Alogient.Cameleon.Forms.Sdk.Util.WebUtil.GetLabelsRessource("Finish"),
                                                 CausesValidation = false
                                             };
                        nextButton.Click += this.nextButton_Click;

                        summaryButtons.Controls.Add(backButton);
                        summaryButtons.Controls.Add(nextButton);
                    }
                }
            }
        }

        protected bool HasPagination(Form form)
        {
            return form.Pages.Count > 1;
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            if (this.FormEnabled)
            {
                int step = this.GetPageStep();

                if (step > 0 && step <= this.TheForm.Pages.Count)
                {
                    // Hide previous page
                    var phPreviousPage = this.FindControl(string.Format(CMFormPage.PageIDFormat, this.TheForm.Pages[step - 1].ID)) as PlaceHolder;
                    if (phPreviousPage != null)
                    {
                        phPreviousPage.Visible = false;
                    }

                    Label previousPageLabel = this.FindControl(string.Format(CMFormPage.PageTitleIDFormat, this.TheForm.Pages[step - 1].ID)) as Label;
                    if (previousPageLabel != null)
                    {
                        previousPageLabel.CssClass = this.TheForm.PageCSS;
                    }
                }

                // If Not finished
                if (step >= 0 && step < this.TheForm.Pages.Count)
                {
                    // Display Page Header
                    this.ShowPageHeader(this.TheForm, true);

                    // Set the current page visibility 
                    var currentPageLabel = this.FindControl(string.Format(CMFormPage.PageTitleIDFormat, this.TheForm.Pages[step].ID)) as Label;
                    if (currentPageLabel != null)
                    {
                        currentPageLabel.CssClass = this.TheForm.SelectedPageCSS;
                    }

                    var phCurrentPage = this.FindControl(string.Format(CMFormPage.PageIDFormat, this.TheForm.Pages[step].ID)) as PlaceHolder;
                    if (phCurrentPage != null)
                    {
                        phCurrentPage.Visible = true;
                    }

                    if (step < this.TheForm.Pages.Count - 1)
                    {
                        // Hide next page
                        var phNextPage = this.FindControl(string.Format(CMFormPage.PageIDFormat, this.TheForm.Pages[step + 1].ID)) as PlaceHolder;
                        if (phNextPage != null)
                        {
                            phNextPage.Visible = false;
                        }

                        var nextPageLabel = this.FindControl(string.Format(CMFormPage.PageTitleIDFormat, this.TheForm.Pages[step + 1].ID)) as Label;
                        if (nextPageLabel != null)
                        {
                            nextPageLabel.CssClass = this.TheForm.PageCSS;
                        }
                    }
                }
                else if (step < 0)
                {
                }
                else 
                {
                    // Hide Page Header
                    this.ShowPageHeader(this.TheForm, false);

                    // Hide Summary Buttons
                    var summaryButtons = this.FindControl(string.Format(SummaryButtonsIDFormat, this.TheForm.ID)) as PlaceHolder;
                    if (summaryButtons != null)
                    {
                        summaryButtons.Visible = false;
                    }

                    // Create Submission
                    var submission = this.CreateSubmission();
                    var summary = new CMFormSummary(submission);

                    if (this.TheForm.ShowSummary && step == this.TheForm.Pages.Count)
                    {
                        // Generate Summary
                        var summaryContainer = this.FindControl(string.Format(SummaryContainerIDFormat, this.TheForm.ID)) as PlaceHolder;

                        if (summaryContainer != null)
                        {
                            summaryContainer.Controls.Add(summary);
                        }

                        // Show Summary Buttons
                        if (summaryButtons != null)
                        {
                            summaryButtons.Visible = true;
                        }
                    }
                    else
                    {
                        // Create Cookie
                        this.CreateFormCookie(this.Page.Response, this.TheForm.ID);

                        // Save Submission
                        submission.Save();

                        // Trigger Form Completed Event
                        var args = new FormEventArgs { Submission = submission };
                        this.OnCompleted(args);

                        if (!string.IsNullOrEmpty(this.TheForm.ConfirmEmail) && !string.IsNullOrEmpty(this.TheForm.EmailFrom))
                        {
                            this.SendEmail(this.TheForm, submission, summary, this.TheForm.EmailFrom, this.TheForm.ConfirmEmail);
                        }

                        if (this.TheForm.Kickback > 0)
                        {
                            CMFormElement KickbackElement = this.FindControl(string.Format(CMFormElement.elementIDFormat, this.TheForm.Kickback)) as CMFormElement;
                            if (KickbackElement != null)
                            {
                                this.SendEmail(this.TheForm, submission, summary, this.TheForm.EmailFrom, KickbackElement.Value);
                            }
                        }

                        if (!string.IsNullOrEmpty(this.TheForm.ReturnUrl)) 
                        {
                            // Go to ReturnUrl
                            this.Page.Response.Redirect(this.TheForm.ReturnUrl);
                        }
                        else
                        {
                            if (this.TheForm.ShowAsSurvey)
                            {
                                var survey = new CMFormSurvey(this.TheForm, submission);
                                this.Controls.Add(survey);
                            }
                            // Show Completed Message or Hide Form
                            var completedLiteral = new Literal { Text = this.TheForm.CompletedText };
                            this.Controls.Add(completedLiteral);
                        }
                    }
                }
            }
        }

        protected List<string> GetFilesName(Submission submission)
        {
            var fileNameList = new List<string>();

            foreach (var v in submission.values)
            {
                if (v.FormElement(submission.CultureCode).InputType == FormInputType.Upload)
                {
                    fileNameList.Add(HttpContext.Current.Server.MapPath(string.Format("{0}{1}", CMSettings.FormMediaUrl, v.Value)));
                }
            }

            return fileNameList;
        }

        protected void SendEmail(Form form, Submission submission, CMFormSummary summary, string emailFrom, string emailTo)
        {
            if (!string.IsNullOrEmpty(CMSettings.SMTPServer))
            {
                var stringWriter = new System.IO.StringWriter();
                var htmlWriter = new HtmlTextWriter(stringWriter);
                summary.RenderControl(htmlWriter);

                var mail = new MailMessage(emailFrom, emailTo);

                List<string> fileNamesList = this.GetFilesName(submission);
                foreach (string s in fileNamesList)
                {
                    mail.Attachments.Add(new Attachment(s));
                }

                var subject = new StringBuilder();

                subject.AppendFormat(Alogient.Cameleon.Forms.Sdk.Util.WebUtil.GetValidatorRessource("Email_Subject"), submission.SubmissionDate.ToString("yyyy/MM/dd hh:mm:ss"), submission.PageUrl, form.Name);

                if (!string.IsNullOrEmpty(form.EmailSubject))
                {
                    mail.Subject = form.EmailSubject;
                }
                else
                {
                    mail.Subject = subject.ToString();
                }

                StringBuilder body = new StringBuilder();

                body.Append(subject.ToString());
                body.Append("<br /><br />");
                body.AppendFormat("Culture : {0}<br />", submission.CultureCode);
                body.Append("<br /><br />");
                body.Append(Alogient.Cameleon.Forms.Sdk.Util.WebUtil.EncodeAccents(stringWriter.ToString()));

                mail.Body = body.ToString();
                mail.IsBodyHtml = true;

                var smtp = new SmtpClient(CMSettings.SMTPServer);
                smtp.Send(mail);
            }
        }

        protected Submission CreateSubmission()
        {
            var submission = new Submission(this.TheForm.ID);

            // Culture Code
            submission.CultureCode = NavigationController.GetCultureCode();
            
            // IP
            submission.IP = this.Page.Request.ServerVariables["REMOTE_ADDR"];
            
            // Original URL
            if (this.Context.Items["originalUrl"] != null)
            {
                submission.PageUrl = this.Context.Items["originalUrl"] as string;
            }
            else
            {
                submission.PageUrl = this.Page.Request.Url.OriginalString;
            }
            
            // Reference URL
            var referenceUrl = this.FindControl("ReferenceUrl") as HiddenField;
            if (referenceUrl != null)
            {
                submission.ReferenceUrl = referenceUrl.Value;
            }

            // Browser, UserAgent
            System.Web.HttpBrowserCapabilities browser = this.Page.Request.Browser;
            submission.UserAgent = string.Format("{0} {1} {2}", browser.Browser, browser.Version, browser.Platform);
            submission.CMForm = this;

            // User PKID & UserName
            if (Forms.Sdk.Util.WebUtil.MembershipEnabled())
            {
                submission.UserName = Forms.Sdk.Util.WebUtil.GetCurrentUsername();
                submission.UserPKID = Forms.Sdk.Util.WebUtil.GetCurrentUserPKID();
            }

            foreach (var page in this.TheForm.Pages)
            {
                foreach (var element in page.Elements)
                {
                    if ((CMServices.IsLive && element.VisibleLive) || (!CMServices.IsLive && element.VisiblePreview))
                    {
                        var val = new SubmissionValue();
                        var formElement = this.FindControl(string.Format(CMFormElement.elementIDFormat, element.ID)) as CMFormElement;
                        if (formElement != null)
                        {
                            val.FormElementID = element.ID;
                            val.Value = formElement.Value;
                            if (element.InputType == FormInputType.Checkbox || element.InputType == FormInputType.Radio ||
                                element.InputType == FormInputType.Select)
                            {
                                foreach (var s in formElement.Values)
                                {
                                    // Generations Selected Options Submission Values
                                    var item = new SubmissionValueItem { SubmissionValue = val, Value = s };

                                    val.Items.Add(item);
                                }
                            }

                            val.Submission = submission;

                            submission.values.Add(val);
                        }
                    }
                }
            }

            return submission;
        }

        protected int GetPageStep()
        {
            int page = 0;
            var formStatusBox = FindControl(Forms.Sdk.Constants.FormStatusBoxID) as TextBox;
            
            if (formStatusBox != null && !string.IsNullOrEmpty(formStatusBox.Text))
            {
                page = Int32.Parse(formStatusBox.Text);
            }

            return page;
        }

        protected void backButton_Click(object sender, EventArgs e)
        {
            this.ChangePageStep(this.GetPageStep() - 1);
        }

        protected void nextButton_Click(object sender, EventArgs e)
        {
            if (((Button)sender).CausesValidation && !Page.IsValid)
            {
                return;
            }

            this.ChangePageStep(this.GetPageStep() + 1);
        }

        protected void ChangePageStep(int step)
        {
            var formStatusBox = FindControl(Forms.Sdk.Constants.FormStatusBoxID) as TextBox;
            
            if (formStatusBox != null)
            {
                formStatusBox.Text = step.ToString();
            }
        }

        protected void GenerateScriptManager()
        {
            ScriptManager scriptMgr = ScriptManager.GetCurrent(Page);

            if (scriptMgr == null)
            {
                scriptMgr = new ScriptManager();
                scriptMgr.ID = string.Format("ScriptManager_{0}", this.TheForm.ID);
                Controls.Add(scriptMgr);
            }
        }

        protected void ShowPageHeader(Forms.Sdk.Items.Form form, bool visible)
        {
            Panel panel = FindControl(string.Format(PagePanelIDFormat, form.ID)) as Panel;
            if (panel != null)
            {
                panel.Visible = visible;
            }
        }

        protected void GeneratePagesHeader(Forms.Sdk.Items.Form form)
        {
            var panel = new Panel { ID = string.Format(PagePanelIDFormat, form.ID) };
            foreach (var page in form.Pages)
            {
                if (this.PageIsVisible(page))
                {
                    var pageTitle = new Label
                                        {
                                            ID = string.Format(CMFormPage.PageTitleIDFormat, page.ID.ToString()),
                                            Text = page.Name,
                                            CssClass = form.PageCSS
                                        };

                    panel.Controls.Add(pageTitle);
                }
            }

            Controls.Add(panel);
        }

        protected bool PageIsVisible(FormPage page)
        {
            return (CMServices.IsLive && page.VisibleLive) || (!CMServices.IsLive && page.VisiblePreview);
        }

        protected void GenerateHiddenFields()
        {
            // RemoteAddress
            var referenceUrl = new HiddenField { ID = "ReferenceUrl" };
            if (!this.Page.IsPostBack)
            {
                referenceUrl.Value = this.Page.Request.ServerVariables["HTTP_REFERER"];
            }

            this.Controls.Add(referenceUrl);

            // Submission Status follower
            this.GenerateSubmissionStatusBox();
        }
        protected void GenerateSubmissionStatusBox()
        {
            var status = new TextBox { ID = Forms.Sdk.Constants.FormStatusBoxID, Visible = false };
            Controls.Add(status);
        }

        protected void GeneratePages(Forms.Sdk.Items.Form form)
        {
            int pageCount = form.Pages.Count;
            foreach (FormPage page in form.Pages)
            {
                if (this.PageIsVisible(page))
                {
                    var phPage = new CMFormPage(page);

                    Controls.Add(phPage);
                }
            }
        }

        protected bool FormCookieExists(HttpRequest request, int formID)
        {
            string name = string.Format("CMForm{0}", formID);
            return request.Cookies[name] != null;
        }

        protected void CreateFormCookie(HttpResponse response, int formID)
        {
            string name = string.Format("CMForm{0}", formID);
            var aCookie = new HttpCookie(name) { Value = name, Expires = DateTime.MaxValue };
            response.Cookies.Add(aCookie);
        }
    }
}
